//
//  Andon_TUTK.m
//  Andon_TUTK
//
//  Created by 宣佚 on 15/6/7.
//  Copyright (c) 2015年 宣佚. All rights reserved.
//

#import "Andon_TUTK.h"
#import "IOTCAPIs.h"
#import "AVAPIs.h"
#import "AVIOCTRLDEFs.h"
#import "AVFRAMEINFO.h"
#import <sys/time.h>
#import <pthread.h>

#define kConnectCount 2
#define AUDIO_BUF_SIZE	4096
#define VIDEO_BUF_SIZE	2000000


static BOOL stopAudioRecvThread = NO;

@implementation Andon_TUTK

id <TUTKClientDelegate> tdelegate;
id <TUTKClientVideoDelegate> tvdelegate;
id <TUTKClientAudioDelegate> tadelegate;

id <TUTKClientDelegate> pdelegate;
int tavIndex;
int tSID;

typedef struct tutklinkinfo
{
    char *tDeviceID;
    char *tUsername;
    char *tPassword;
}tlink;


-(void)setStopAudioRecvThread{
    stopAudioRecvThread = YES;
}
- (void)start:(NSString *)DeviceID userName:(NSString *)username passWord:(NSString *)password
{
    tdelegate = self.delegate;
    
    tlink *info = malloc(sizeof(tlink));
    
    info->tDeviceID = malloc(1000);
    info->tDeviceID[0] = '\0';
    strcpy(info->tDeviceID,[DeviceID UTF8String]);
    
    info->tUsername = malloc(1000);
    info->tUsername[0] = '\0';
    strcpy(info->tUsername,[username UTF8String]);
    
    info->tPassword = malloc(1000);
    info->tPassword[0] = '\0';
    strcpy(info->tPassword,[password UTF8String]);
    
    pthread_t main_thread;
    int result = pthread_create(&main_thread, NULL, &start_main, info);
    if (result == 0) {
        NSLog(@"result创建线程 OK");
    } else {
        if ([self.delegate respondsToSelector:@selector(Tutk_Connected_Failure:)]) {
            [self.delegate Tutk_Connected_Failure:[NSString stringWithFormat:@"result创建线程失败 %d", result]];
        }
    }
    pthread_detach(main_thread);
}

-(void)startVideoQueue:(int)avIndex
{
    tvdelegate = self.vdelegate;
    
    if ([tvdelegate respondsToSelector:@selector(Tutk_Video_StartConnection)]) {
        [tvdelegate Tutk_Video_StartConnection];
    }
    
    if (start_ipcam_stream_video(avIndex)>0)
    {
        pthread_t ThreadVideo_ID;
        int VideoResult = pthread_create(&ThreadVideo_ID, NULL, &thread_ReceiveVideo, (void *)&avIndex);
        if (VideoResult == 0) {
            NSLog(@"VideoResult创建线程 OK");
            if ([tvdelegate respondsToSelector:@selector(Tutk_Video_Connected_Success)]) {
                [tvdelegate Tutk_Video_Connected_Success];
            }
        }
        else {
            if ([tvdelegate respondsToSelector:@selector(Tutk_Video_Connected_Failure:ErrorType:)]) {
                [tvdelegate Tutk_Video_Connected_Failure:[NSString stringWithFormat:@"VideoResult创建线程失败 %d", VideoResult] ErrorType:TUTK_AV_OTHER_ERROR];
            }
        }
         pthread_detach(ThreadVideo_ID);
    }
    else {
        if ([tvdelegate respondsToSelector:@selector(Tutk_Video_Connected_Failure:ErrorType:)]) {
            [tvdelegate Tutk_Video_Connected_Failure:@"打开视频失败" ErrorType:TUTK_AV_OTHER_ERROR];
        }
    }
}

-(void)stopVideoQueue:(int)avIndex
{
    tvdelegate = self.vdelegate;
    int ret;
    
    SMsgAVIoctrlAVStream ioMsg;
    memset(&ioMsg, 0, sizeof(SMsgAVIoctrlAVStream));
    if ((ret = avSendIOCtrl(avIndex, IOTYPE_USER_IPCAM_STOP, (char *)&ioMsg, sizeof(SMsgAVIoctrlAVStream)) < 0))
    {
        NSLog(@"start_ipcam_stream_failed[%d]", ret);
        if ([tvdelegate respondsToSelector:@selector(Tutk_Video_DisConnected_Failure)]) {
            [tvdelegate Tutk_Video_DisConnected_Failure];
        }
    }
    
    if ([tvdelegate respondsToSelector:@selector(Tutk_Video_DisConnected_Success)]) {
        [tvdelegate Tutk_Video_DisConnected_Success];
    }
}

-(void)startAudioQueue:(int)avIndex WithAudioFormat:(ENUM_AUDIO_FORMAT) format
{
    tadelegate = self.adelegate;
    
    if ([tadelegate respondsToSelector:@selector(Tutk_Audio_StartConnection)]) {
        [tadelegate Tutk_Audio_StartConnection];
    }
    SMsgAVIoctrlSetAudioFormatReq sendMsg;
    sendMsg.channel= avIndex;
    sendMsg.format = format;
    self.audioFormat = format;
    switch (self.audioFormat) {
        case AUDIO_FORMAT_AAC:
            NSLog(@"设置音频格式为 AAC");
            break;
            case AUDIO_FORMAT_G711A:
            NSLog(@"设置音频格式为 G711A");
            break;
        case AUDIO_FORMAT_PCM:
            NSLog(@"设置音频格式为 PCM");
            break;
        default:
            NSLog(@"不支持的音频格式");
            break;
    }
    int ret = avSendIOCtrl(avIndex, IOTYPE_USER_IPCAM_SETAUDIOFORMAT_REQ, (char *)&sendMsg, sizeof(SMsgAVIoctrlSetAudioFormatReq));
    
    if (ret != AV_ER_NoERROR)
    {
        NSLog(@"SetAudioFormat() Error! [%d]", ret);
        return ;
    }else{
        NSLog(@"SetAudioFormat() Successfully! [%d]",ret);
    }
    
    if (start_ipcam_stream_audio(avIndex)>0)
    {
        pthread_t ThreadAudio_ID;
        int AudioResult = pthread_create(&ThreadAudio_ID, NULL, &thread_ReceiveAudio, (void *)&avIndex);
        if (AudioResult == 0) {
            NSLog(@"AudioResult创建线程 OK");
            if ([tadelegate respondsToSelector:@selector(Tutk_Audio_Connected_Success)]) {
                [tadelegate Tutk_Audio_Connected_Success];
            }
        }
        else {
            if ([tadelegate respondsToSelector:@selector(Tutk_Connected_Failure:)]) {
                [tadelegate Tutk_Audio_Connected_Failure:[NSString stringWithFormat:@"AudioResult创建线程失败 %d", AudioResult] ErrorType:TUTK_AV_OTHER_ERROR];
            }
        }
        pthread_detach(ThreadAudio_ID);
    }
    else {
        if ([tadelegate respondsToSelector:@selector(Tutk_Connected_Failure:)]) {
            [tadelegate Tutk_Audio_Connected_Failure:@"打开音频失败" ErrorType:TUTK_AV_OTHER_ERROR];
        }
    }
}

-(void)stopAudioQueue:(int)avIndex
{
    int ret;
    
    SMsgAVIoctrlAVStream ioMsg;
    memset(&ioMsg, 0, sizeof(SMsgAVIoctrlAVStream));
    if ((ret = avSendIOCtrl(avIndex, IOTYPE_USER_IPCAM_AUDIOSTOP, (char *)&ioMsg, sizeof(SMsgAVIoctrlAVStream)) < 0))
    {
        NSLog(@"start_ipcam_stream_failed[%d]", ret);
        if ([_adelegate respondsToSelector:@selector(Tutk_Audio_DisConnected_Failure)]) {
            [_adelegate Tutk_Audio_DisConnected_Failure];
        }
    }
    
    if ([_adelegate respondsToSelector:@selector(Tutk_Audio_DisConnected_Success)]) {
        [_adelegate Tutk_Audio_DisConnected_Success];
    }
}
-(void)stop
{
    avClientStop(tavIndex);
    NSLog(@"avClientStop OK");
    IOTC_Session_Close(tSID);
    NSLog(@"IOTC_Session_Close OK");
    avDeInitialize();
    IOTC_DeInitialize();
    NSLog(@"StreamClient exit...");
    tSID = 0;
    tavIndex = 0;
    if ([self.delegate respondsToSelector:@selector(Tutk_DisConnected_Success)]) {
        [self.delegate Tutk_DisConnected_Success];
    }
}
long _getTickCount()
{
    struct timeval tv;
    if (gettimeofday(&tv, NULL) != 0)
        return 0;
    
    return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
}

void *thread_ReceiveAudio(void *arg)
{
    int avIndex = *(int *)arg;
    char buf[AUDIO_BUF_SIZE];
    unsigned int frmNo;
    int ret;
    FRAMEINFO_t frameInfo;
    
    while (!stopAudioRecvThread)
    {
        ret = avCheckAudioBuf(avIndex);
        if (ret < 0) break;
        if (ret < 3) // determined by audio frame rate
        {
            usleep(120000);
            continue;
        }
        
        ret = avRecvAudioData(avIndex, buf, AUDIO_BUF_SIZE, (char *)&frameInfo, sizeof(FRAMEINFO_t), &frmNo);
        
        if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE)
        {
            if ([tadelegate respondsToSelector:@selector(Tutk_Audio_Connected_Failure:ErrorType:)]) {
                [tadelegate Tutk_Audio_Connected_Failure:@"[thread_ReceiveAudio] AV_ER_SESSION_CLOSE_BY_REMOTE" ErrorType:TUTK_AV_CLOSE_BY_REMOTE];
            }
            break;
        }
        else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT)
        {
            if ([tadelegate respondsToSelector:@selector(Tutk_Audio_Connected_Failure:ErrorType:)]) {
                [tadelegate Tutk_Audio_Connected_Failure:@"[thread_ReceiveAudio] AV_ER_REMOTE_TIMEOUT_DISCONNECT" ErrorType:TUTK_AV_TIMEOUT_DISCONNECT];
            }
            break;
        }
        else if(ret == IOTC_ER_INVALID_SID)
        {
            if ([tadelegate respondsToSelector:@selector(Tutk_Audio_Connected_Failure:ErrorType:)]) {
                [tadelegate Tutk_Audio_Connected_Failure:@"[thread_ReceiveAudio] Session cant be used anymore" ErrorType:TUTK_AV_INVALID_SID];
            }
            break;
        }
        else if (ret == AV_ER_LOSED_THIS_FRAME)
        {
            if ([tadelegate respondsToSelector:@selector(Tutk_Audio_Connected_Failure:ErrorType:)]) {
                [tadelegate Tutk_Audio_Connected_Failure:@"[thread_ReceiveAudio] Losed This Frame." ErrorType:TUTK_AV_OTHER_ERROR];
            }
            continue;
        }
        
        if (ret > 0  && [tadelegate respondsToSelector:@selector(tutk_onAudioData:andlength:)]) {
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken,^{
            switch(frameInfo.codec_id){
                case MEDIA_CODEC_AUDIO_AAC:
                    NSLog(@"实际接收到的音频格式为: AAC");
                    break;
                case MEDIA_CODEC_AUDIO_G711A:
                    NSLog(@"实际接收到的音频格式为: G711A");
                    break;
                case MEDIA_CODEC_AUDIO_PCM:
                    NSLog(@"实际接收到的音频格式为: PCM");
                    break;
                default:
                    NSLog(@"实际接收到不支持的音频格式-[%d]", frameInfo.codec_id);
                    break;
            }
            });
            
            [tadelegate tutk_onAudioData:buf andlength:ret];
        }
    }
    
    NSLog(@"[thread_ReceiveAudio] thread exit");
    return 0;
}
int start_ipcam_stream_audio (int avIndex)
{
    int ret;
    unsigned short val = 0;
    
    if ((ret = avSendIOCtrl(avIndex, IOTYPE_INNER_SND_DATA_DELAY, (char *)&val, sizeof(unsigned short)) < 0))
    {
        NSLog(@"start_ipcam_stream_failed[%d]", ret);
        return 0;
    }
    
    SMsgAVIoctrlAVStream sendMsg;
    sendMsg.channel= avIndex;
    
    ret = avSendIOCtrl(avIndex, IOTYPE_USER_IPCAM_AUDIOSTART, (char *)&sendMsg, sizeof(SMsgAVIoctrlAVStream));
    
    if (ret != AV_ER_NoERROR)
    {
        NSLog(@"Audio_Start() Error! [%d]", ret);
        return 0 ;
        
    }else{
        NSLog(@"Audio_Start() Successfully! [%d]",ret);
        return 1;
    }
}

void *thread_ReceiveVideo(void *arg)
{
    int avIndex = *(int *)arg;
    char *buf = malloc(VIDEO_BUF_SIZE);
    unsigned int frameNo;
    int ret;
    FRAMEINFO_t frameInfo;
    
    while (1)
    {
        ret = avRecvFrameData(avIndex, buf, VIDEO_BUF_SIZE, (char*)&frameInfo, sizeof(FRAMEINFO_t), &frameNo);
        
        if(ret == AV_ER_DATA_NOREADY)
        {
            usleep(30000);
            continue;
        }
        else if(ret == AV_ER_LOSED_THIS_FRAME)
        {
            NSLog(@"Lost video frame NO[%d]", ret);
            continue;
        }
        else if(ret == AV_ER_INCOMPLETE_FRAME)
        {
            NSLog(@"Incomplete video frame NO[%d]", ret);
                //            continue;
        }
        else if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE)
        {
            if ([tvdelegate respondsToSelector:@selector(Tutk_Audio_Connected_Failure:ErrorType:)]) {
                [tvdelegate Tutk_Video_Connected_Failure:@"[thread_ReceiveVideo] AV_ER_SESSION_CLOSE_BY_REMOTE" ErrorType:TUTK_AV_CLOSE_BY_REMOTE];
            }
            break;
        }
        else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT)
        {
            if ([tvdelegate respondsToSelector:@selector(Tutk_Audio_Connected_Failure:ErrorType:)]) {
                [tvdelegate Tutk_Video_Connected_Failure:@"[thread_ReceiveVideo] AV_ER_REMOTE_TIMEOUT_DISCONNECT" ErrorType:TUTK_AV_TIMEOUT_DISCONNECT];
            }
            break;
        }
        else if(ret == IOTC_ER_INVALID_SID)
        {
            if ([tvdelegate respondsToSelector:@selector(Tutk_Audio_Connected_Failure:ErrorType:)]) {
                [tvdelegate Tutk_Video_Connected_Failure:@"[thread_ReceiveVideo] Session cant be used anymore" ErrorType:TUTK_AV_INVALID_SID];
            }
            break;
        }
        
        if( ret > 0)
        {
            NSLog(@"frame NO[%d]", ret);
            if ([tvdelegate respondsToSelector:@selector(tutk_onVideoData:andlength:andframeindex:)]) {
                [tvdelegate tutk_onVideoData:buf andlength:ret andframeindex:avIndex];
            }
        }
    }
    free(buf);
    NSLog(@"[thread_ReceiveVideo] thread exit");
    return 0;
}
int start_ipcam_stream_video (int avIndex)
{
    int ret;
    
    SMsgAVIoctrlAVStream ioMsg;
    memset(&ioMsg, 0, sizeof(SMsgAVIoctrlAVStream));
    if ((ret = avSendIOCtrl(avIndex, IOTYPE_USER_IPCAM_START, (char *)&ioMsg, sizeof(SMsgAVIoctrlAVStream)) < 0))
    {
        NSLog(@"start_ipcam_stream_failed[%d]", ret);
        return 0;
    }
    
    return 1;
}

void *start_main (void *arg)
{
    if ([tdelegate respondsToSelector:@selector(Tutk_StartConnection)]) {
        [tdelegate Tutk_StartConnection];
    }
    
    tlink *tt = (tlink *)arg;
    char *td = tt->tDeviceID;
    char *tu = tt->tUsername;
    char *tp = tt->tPassword;
    
    int ret = 0;
    int SID;
    unsigned short nUdpPort = (unsigned short)(10000 + (_getTickCount() % 10000));
    ret = IOTC_Initialize(nUdpPort, "50.19.254.134", "122.248.234.207", "m4.iotcplatform.com", "m5.iotcplatform.com");
    NSLog(@"IOTC_Initialize() ret = %d", ret);
    
    if (ret != IOTC_ER_NoERROR) {
        NSLog(@"IOTCAPIs exit...");
        return NULL;
    }
    
    avInitialize(5);
    
    SID = IOTC_Connect_ByUID(td);
    tSID = SID;
    
    NSLog(@"Step 2: call IOTC_Connect_ByUID2(%s) ret(%d).......\n", td, SID);
    struct st_SInfo Sinfo;
    ret = IOTC_Session_Check(SID, &Sinfo);
    
    if (ret >= 0)
    {
        if(Sinfo.Mode == 0)
        {
            NSLog(@"Device is from %s:%d[%s] Mode=P2P\n",Sinfo.RemoteIP, Sinfo.RemotePort, Sinfo.UID);
        }
        else if (Sinfo.Mode == 1)
        {
            NSLog(@"Device is from %s:%d[%s] Mode=RLY\n",Sinfo.RemoteIP, Sinfo.RemotePort, Sinfo.UID);
        }
        else if (Sinfo.Mode == 2)
        {
            NSLog(@"Device is from %s:%d[%s] Mode=LAN\n",Sinfo.RemoteIP, Sinfo.RemotePort, Sinfo.UID);
        }
    }
    
    unsigned int srvType;
    int avIndex = avClientStart(SID, tu, tp, 20000, &srvType, 0);
    tavIndex = avIndex;
    NSLog(@"Step 3: call avClientStart(%s),(%s).......\n", tu,tp);
    
    if(avIndex < 0)
    {
        if ([tdelegate respondsToSelector:@selector(Tutk_Connected_Failure:)]) {
            [tdelegate Tutk_Connected_Failure:[NSString stringWithFormat:@"avClientStart failed[%d]\n", avIndex]];
        }
        return NULL;
    }
    else
    {
        if ([tdelegate respondsToSelector:@selector(Tutk_Connected_Success:)]) {
            [tdelegate Tutk_Connected_Success:avIndex];
        }
    }
    return NULL;
}
@end
